<?php
/**
* Class handling all the sessions in the application
* @package utilities
* @author ayo
* @since Dec 12, 2011
* @version 1.0
* @see
*/
class SessionHandler
{
	/**
	* instance of the SessionHandler class
	* @var Object
	* @access private 
	* @static
	*/
	private static $o_instance;
	
	/**
	 * 
	 * Holds the current session key
	 * @var string
	 * @access protected
	 */
	protected $s_sessionKey;
	
	/**
	 * 
	 * Holds the salt to be used in this session class
	 * @var string
	 * @access protected
	 */
	protected $s_sessionSalt;	
	
	/**
	*
	* Holds the second salt to be used in this session class
	* @var string
	* @access protected
	*/
	protected $s_sessionSaltB;
	
	/**
	 * 
	 * Holds the static generated key
	 * @var string
	 * @access protected
	 */
	protected $s_staticKey;
	
	/**
	 * 
	 * Holds the child key to be used for identifying the current sessions key and contents
	 * @var string
	 * @access protected
	 */
	protected $s_sessionChildKey;
	
	/**
	* Constructor
	* initilizes the neccessary variables in the class when creating it
	* @access private
	*/
	private function __construct()
	{
		//set to false a default start
		$this->s_sessionSalt = md5('test_salt');
		$this->s_sessionSaltB = md5('test_salt2');
		$this->s_sessionChildKey = md5('browseKey');
	}
	
	/**
	* Handles the initialization of the class<br>
	* it has a static reference to its instance making it a singleton
	*
	* @return Object instance
	* @access public
	* @static
	*/
	public static function getInstance()
	{
		if(!isset(self::$o_instance) ||  self::$o_instance == null)
		{
			self::$o_instance = new SessionHandler();
		}
		return self::$o_instance;
	}
	
	public function start()
	{
		session_name('_claycode_application_session');
		session_start();
		$this->create();
	}
	
	/**
	 * 
	 * Creates the session
	 * @access public
	 */
	private function create()
	{
		if(!isset($_SESSION[$this->makeStaticKey()])){
			//check if the session has already been started somewhere in the same instance
			//start the session
			//regenerate the id first
			session_regenerate_id();
			$s_staticKey = $this->makeStaticKey();
			$s_randKey = $this->makeKey();
			// two way keys
			
			//static key used to identify the browsing key created inside that is identified by the child key created
			$_SESSION[$s_staticKey] = array(
				$this->s_sessionChildKey=> $s_randKey
			);
			
			//the real session variables are held here
			//concatenate the random browsing key and the static key for obfuscation
			//at least a bit more confusion
			$_SESSION[$s_randKey . $s_staticKey] = true;
		}			
	}
	
	public function getSessVarKey()
	{
		return $this->getCurrentBrowsingKey();
	}
	
	public function browsingSafe()
	{
		if(isset( $_SESSION[$this->getCurrentBrowsingKey() . $this->makeStaticKey()])){
			return true;
		}else{
			return false;
		}
	}
	/**
	 * 
	 * Prolongs a session
	 * @access public
	 */
	public function keepAlive()
	{
		
	}
	
	/**
	*
	* Reads from the current session array
	* @param string $s_key
	*/
	public function read($s_key = null)
	{
		if($s_key != null){
			if(isset($_SESSION[$this->makeStaticKey()])){
				$arr_currSessionArray = $this->getCurrentSessionArray();
				if(isset($arr_currSessionArray[$s_key])){
					return $arr_currSessionArray[$s_key];
				}else{
					return false;
				}
			}
		}	
	}
	
	/**
	 * Writes to the session array based on the provided key and the value to write on the session array
	 * 
	 * @param string $s_key
	 * @param Object $o_value
	 * @access public
	 * @return boolean flag for the write success
	 */
	public function write($s_key = null, $o_value = null)
	{
		if($s_key != null && $o_value != null){
			if(isset($_SESSION[$this->makeStaticKey()])){
				$_SESSION[$this->getCurrentBrowsingKey() . $this->makeStaticKey()][$s_key] = $o_value;
				return true;
			}else{
				return false;
			}
		}
		
	}
	
	/**
	 *
	 * Gets the current session array that is used
	 * @access private
	 */
	private function getCurrentSessionArray()
	{
		return $_SESSION[$this->getCurrentBrowsingKey() . $this->makeStaticKey()];
	}
	
	private function getCurrentBrowsingKey()
	{
		return $_SESSION[$this->makeStaticKey()][$this->s_sessionChildKey];
	}
	
	/**
	 * 
	 * Destroys a session
	 * @access public
	 */
	public function destroy()
	{
		$this->clean();
		session_destroy();
		
	}
	
	/**
	 * Garbage collection of the session variables
	 * @access public
	 */
	public function clean()
	{
		unset($_SESSION[$this->getCurrentBrowsingKey()]);
		unset($_SESSION[$this->makeStaticKey()]);
		$_SESSION = null;
		//unset($_SESSION);
		self::$o_instance = null;
		gc_collect_cycles();
	}
	
	/**
	 * 
	 * Creates the initial static key for storing things in the session
	 * @access private 
	 * @return string static generated key
	 */
	private function makeStaticKey()
	{
		
		$s_staticKey =  $this->s_sessionSalt . $_SERVER['HTTP_USER_AGENT'];
		$s_staticKey .= hash('md5',$_SERVER['REMOTE_ADDR']);
		return hash('md5', sha1($s_staticKey));
		
	}
	
	/**
	 * Creates a unique key for usage in the brwoser key for sessions
	 * @access private
	 */
	private function makeKey()
	{
		$s_userAgent = $_SERVER['HTTP_USER_AGENT'];
		$s_timestamp = date("Y-m-d H:i:s:ss");
		$s_first_key = substr($s_timestamp, rand(2,9), rand(2,9));
		$s_second_key = substr($s_userAgent, rand(2,9), rand(2,9));
		$s_third_key = substr($s_timestamp , rand(1,8), rand(1,8));
		$s_fourth_key = substr(md5(uniqid()) , rand(1,8), rand(1,8));
		$s_concat_Key = $s_first_key.$s_second_key.$s_third_key.$s_fourth_key;
		$s_sessionKey = sha1(hash('md5',$s_concat_Key));
		return $s_sessionKey;
	}
	
	
	private function generateSessionName()
	{
		$s_sessionName = '';
		$arr_alphabet = range('a', 'z') ;
		for($i=1;$i<=30;$i++){
			//generate 20 random numbers
			$i_randNum = rand(0, 25);
			$s_sessionName .= $arr_alphabet[$i_randNum];
		}
		
		return $s_sessionName;
	}
	
}